package com.example.juc;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

public class CasTest {

    static ExecutorService executorService = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {


        //test5();
        //test6();

        test7();
    }

    /**
     * cas简单演示
     */
    public static void test1(){

        AtomicInteger atomicInteger = new AtomicInteger(1);

        new Thread(()->{

            boolean b = atomicInteger.compareAndSet(1, 2);

            System.out.println("结果："+b+" value "+atomicInteger.get());

            b = atomicInteger.compareAndSet(1, 2);

            System.out.println("结果："+b+" value "+atomicInteger.get());

        }).start();

    }

    /**
     * ABA问题
     */
    public static void test2(){

        AtomicInteger atomicInteger = new AtomicInteger(1);

        new Thread(()->{

            boolean b = atomicInteger.compareAndSet(1, 2);

            System.out.println("结果："+b+" value "+atomicInteger.get());

            b = atomicInteger.compareAndSet(2, 1);

            System.out.println("结果："+b+" value "+atomicInteger.get());

            b = atomicInteger.compareAndSet(1, 2);

            System.out.println("结果："+b+" value "+atomicInteger.get());

        }).start();

    }

    /**
     * 解决ABA问题
     */
    public static void test3(){

        AtomicStampedReference atomicInteger = new AtomicStampedReference<>(1,1);

        new Thread(()->{
            boolean b = atomicInteger.compareAndSet(1, 2, atomicInteger.getStamp(), atomicInteger.getStamp()+1);

            System.out.println("线程1结果："+b+" value "+atomicInteger.getReference()+" version "+atomicInteger.getStamp() );

            /**
             * 同时判断 值 和 版本号是否都满足
             */

            b = atomicInteger.compareAndSet(2, 1,atomicInteger.getStamp(), atomicInteger.getStamp()+1);

            System.out.println("线程1结果："+b+" value "+atomicInteger.getReference()+" version "+atomicInteger.getStamp() );
        }).start();


        new Thread(()->{

            int stamp = atomicInteger.getStamp();

            System.out.println("线程2 version "+stamp );

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean b = atomicInteger.compareAndSet(1, 2, stamp, stamp+1);

            System.out.println("线程2结果："+b+" value "+atomicInteger.getReference()+" version "+atomicInteger.getStamp() );

        }).start();
    }

    /**
     * 测试cas中的自旋,实现原子操作
     */
    public static void test4(){

        AtomicInteger atomicInteger = new AtomicInteger();

        new Thread(()->{

            int andAdd = atomicInteger.getAndUpdate((v->{
                System.out.println("设置+1");
                return v+1;
            }));

            System.out.println("设置+1:"+atomicInteger.get());

        }).start();

        new Thread(()->{

            int andAdd = atomicInteger.getAndUpdate((v->{
                System.out.println("设置+2");
                return v+2;
            }));

            System.out.println("设置+2:"+atomicInteger.get());

        }).start();

    }

    /**
     * 测试cas耗时，计算累加
     */
    public static void test5() throws ExecutionException, InterruptedException {

        long l = System.currentTimeMillis();

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        AtomicInteger atomicInteger = new AtomicInteger();

        int size=5000000;

        CountDownLatch countDownLatch = new CountDownLatch(size);

        for(int i=0;i<size;i++){
            int finalI = i;
            executorService.submit(()->{
                atomicInteger.updateAndGet(pre->{
                    //System.out.println(pre);
                    compute();
                    int v=pre+ finalI;
                    return v;
                });

                countDownLatch.countDown();
            });
        }

        countDownLatch.await();

        System.out.println(atomicInteger.get());
        System.out.println("耗时:"+(System.currentTimeMillis()-l));




        executorService.shutdown();
    }

    /**
     * 测试cas耗时，计算累加
     */
    public static void test6() throws ExecutionException, InterruptedException {

        long l = System.currentTimeMillis();

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        AtomicInteger atomicInteger = new AtomicInteger();

        int size=5000000;

        CountDownLatch countDownLatch = new CountDownLatch(size);

        for(int i=0;i<size;i++){
            int finalI1 = i;
            executorService.submit(()->{
                synchronized (countDownLatch){
                    compute();
                    atomicInteger.set(atomicInteger.get()+ finalI1);
                    countDownLatch.countDown();
                }
            });
        }

        countDownLatch.await();

        System.out.println(atomicInteger.get());

        System.out.println("耗时:"+(System.currentTimeMillis()-l));

        executorService.shutdown();
    }


    /**
     * 支付场景，用户连续请求
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void test7() throws ExecutionException, InterruptedException{

        //假设用户有100块钱
        AtomicInteger atomicInteger = new AtomicInteger(100);

        //网络延迟，用户多次点击请求支付
        for(int i=0;i<10;i++) {
            boolean b = atomicInteger.compareAndSet(100, 70);
        }

        System.out.println("支付成功 余额:"+atomicInteger.get());
    }


    private static void sleep(){
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static void compute(){
        int i=0;
        int j=10;
        int k=10*i*j+1;
        k=k*k*k*k*10*2+6;
    }
}
